import types
import sys
import os

from django.contrib import admin
from django.forms.models import BaseModelFormSet, modelformset_factory, InlineForeignKeyField
from django.contrib.admin import options
from mongomodel import models

def embedded_inline_factory( field ):

    attrs = {
            'model' : field.doc,
            'parent_field' : field,
            }

    return type( field.doc._meta.object_name + 'Inline', ( EmbeddedModelAdmin,), attrs )

class MongoModelAdmin(admin.ModelAdmin):

    def __init__(self, model, admin_site ):

        for field in model._meta.fields:
            if isinstance( field, (models.DocumentField, models.DocumentListField ) ):
                if self.exclude is None:
                    self.exclude = []
                self.exclude.append( field.name )
                self.inlines.append( embedded_inline_factory( field ) )

        super(MongoModelAdmin,self).__init__(model, admin_site)


class EmbeddedParent(object):

    name = '_fk'
    def __init__(self , parent, parent_field):
        self.parent = parent
        self.parent_field_name = parent_field.name
        self.rel = models.ManyToOneRel( parent, parent._meta.pk.name )
        self
        pass

    def get_records(self, inst):
        records = getattr(inst, self.parent_field_name)
        if records is None:
            return []
        if not isinstance( records , list ):
            return [records]

        return records


class EmbeddedInlineFormSet(BaseModelFormSet):

    def __init__(self, data=None, files=None, instance=None,
                     save_as_new=False, prefix=None, queryset=None):

        self.instance = instance
        self.save_as_new = save_as_new
        self.records = self.fk.get_records( instance )
        super(EmbeddedInlineFormSet, self).__init__(data, files, prefix=prefix)
        #super(BaseInlineFormSet, self).__init__(data, files, prefix=prefix,
        #            queryset=qs)

    def initial_form_count(self):
        if self.save_as_new:
            return 0

        return len(self.records)


    def total_form_count(self):
        if self.save_as_new:
            return super(EmbeddedInlineFormSet, self).initial_form_count()
    
        total = super(EmbeddedInlineFormSet, self).total_form_count()
        return total

    def _construct_form(self, i, **kwargs):

        if i < self.initial_form_count() and not kwargs.get('instance'):
            kwargs['instance'] = self.records[i]

        form = super(BaseModelFormSet, self)._construct_form(i, **kwargs)
        if self.save_as_new:
            raise NotImplementedError 
            form.data[ form.add_prefix(self._pk_field.name)] = None
            form.data[ form.add_prefix(self.fk.name)] = None

        #setattr(form.instance, self.fk.get_attname(), self.instance.pk )
        return form


    def save_new(self, form, commit=True):
        raise NotImplementedError

    def add_fields(self, form, index):

        super(BaseModelFormSet, self).add_fields(form, index)

        kwargs = {}
        form.fields[self.fk.name] = InlineForeignKeyField(self.instance, **kwargs)
        if form._meta.fields:
            raise NotImplementedError
            if isinstance(form._meta.fields, tuple):
                form._meta.fields = list(form._meta.fields)
            form._meta.fields.append(self.fk.name)



    def get_unique_error_message(self, unique_check):
        raise NotImplementedError

    def get_default_prefix(cls):
        from django.db.models.fields.related import RelatedObject
        return RelatedObject(cls.fk.rel.to, cls.model, cls.fk).get_accessor_name().replace('+','')

    get_default_prefix = classmethod(get_default_prefix)

    def get_queryset(self):
        return self.records

class EmbeddedModelAdmin(admin.TabularInline):

    formset = EmbeddedInlineFormSet
    extra = 0

    def get_formset(self, request, obj=None, **kwargs):
        """Returns a BaseInlineFormSet class for use in admin add/change views."""

        # obj is parent instance
        if self.declared_fieldsets:
            fields = flatten_fieldsets(self.declared_fieldsets)
        else:
            fields = None
        if self.exclude is None:
            exclude = []
        else:
            exclude = list(self.exclude)
        exclude.extend(kwargs.get("exclude", []))
        exclude.extend(self.get_readonly_fields(request, obj))
        # if exclude is an empty list we use None, since that's the actual
        # default
        exclude = exclude or None
        defaults = {
            "form": self.form,
            "formset": self.formset,
            #"fk_name": self.fk_name,
            "fields": fields,
            "exclude": exclude,
            "formfield_callback": models.curry(self.formfield_for_dbfield, request=request),
            "extra": self.extra,
            "max_num": self.max_num,
            "can_delete": self.can_delete,
        }
        defaults.update(kwargs)
        FormSet = modelformset_factory(self.model, **defaults)
        FormSet.fk = EmbeddedParent(self.parent_model, self.parent_field)
        return FormSet


class ListWidget(forms.MultiWidget):

    def __init__(self, field, attrs=None):
        
        self.field = field
        form_field = field.formfield()
        self.base_widget = form_field.widget
        super(forms.MultiWidget, self).__init__(attrs)

    def render(self, name, value, attrs=None):

        self.widgets = [isinstance(self.base_widget, type) and self.base_widget() or self.base_widget for v in range(len(value)+1)]
        return super(ListWidget, self).render(name, value,attrs)

    def __deepcopy__(self, memo):
        obj = super(forms.MultiWidget, self).__deepcopy__(memo)
        obj.base_widget = copy.deepcopy(self.base_widget)
        obj.widgets = copy.deepcopy(self.widgets)
        return obj



class AdminListWidget(ListWidget):

    def __init__(self, field, attrs=None):
        
        super(AdminListWidget, self).__init__(field, attrs)
        form_field = options.BaseModelAdmin().formfield_for_dbfield( field )
        self.base_widget = form_field.widget


class ListFormField(forms.MultiValueField):

    widget = ListWidget

    def __init__(self, field=None, *args, **kwargs):

        self.field = field

        widget = kwargs.pop('widget', self.widget)
        widget = widget( field )

        super(ListFormField, self).__init__( widget=widget,*args, **kwargs )

        self.widget = widget

    def clean(self, value):
        raise NotImplementedError

    def to_python(self, value):
        raise NotImplementedError

options.BaseModelAdmin.formfield_overrides = {
        ListField: { 'widget' : AdminListWidget  },
}
